package com.unibuy.smartdevice.controller;

import com.unibuy.smartdevice.MyApp;
import com.unibuy.smartdevice.devices.DevXinYuan;
import com.unibuy.smartdevice.devices.PortTools;
import com.unibuy.smartdevice.devices.Rs232Dev;
import com.unibuy.smartdevice.exception.ErrorCode;
import com.unibuy.smartdevice.exception.Logs;
import com.unibuy.smartdevice.exception.LogsIOException;
import com.unibuy.smartdevice.exception.LogsUnsupportedOperationException;
import com.unibuy.smartdevice.tools.HandlerMain;

import java.util.HashMap;
import java.util.Map;

public class DevXinYuanController extends DevController {
    private Logs logs;
    private Rs232Dev rs232Dev;
    private DevXinYuan devXinYuan;
    private static int temperature = 0;
    private static double temp = 0.0;
    public static final Map<Byte, DevXinYuan.VMC> vmcMap = new HashMap<>();
    // 靜態區塊，初始化 Map
    static {
        for (DevXinYuan.VMC vmc : DevXinYuan.VMC.values()) {
            vmcMap.put(vmc.getBytes()[0], vmc);
        }
    }

    public DevXinYuan getDevXinYuan() {
        return devXinYuan;
    }

    public DevXinYuanController(HandlerMain handlerMain) {
        super( 50, handlerMain);
        this.logs = new Logs(getClass());
        this.devXinYuan = new DevXinYuan();
        try {
            this.rs232Dev = new Rs232Dev(MyApp.getInstance().getComPort1ByXinYuan());
            devXinYuan.setRun(true);
            logs.debug("下位機連接");
        } catch (LogsUnsupportedOperationException | LogsIOException e) {
//            getLogs().error(ErrorCode.DEV_ERROR, "@下位機連接錯誤", handlerMain);
            getLogs().warning(e);
            setRun(false);
        }
    }

    @Override
    protected void close(HandlerMain handlerMain) {
        devXinYuan.setRun(false);
        try {
            this.rs232Dev.closePort();
        } catch (LogsIOException e) {
            getLogs().warning(e);
        }
    }

    @Override
    protected HandlerMain setHandlerMain() {
        return getSrcHandlerMain();
    }

    @Override
    protected void execute(HandlerMain handlerMain) {
        devXinYuanRun(handlerMain);
    }

    public void devXinYuanRun(HandlerMain handlerMain) {
        while (isRun()) {
            try {
                byte[] stx = rs232Dev.readToMatch(DevXinYuan.VMC.VMC_FAFB_STX.getBytes(),  0);

                byte[] vmcCmd = new byte[2];
                rs232Dev.read(vmcCmd);
                byte[] vmcData = new byte[vmcCmd.length==2?vmcCmd[1]:0];
                rs232Dev.read(vmcData);
                byte[] vmcXor = new byte[1];
                rs232Dev.read(vmcXor);

                Byte key = Byte.valueOf(vmcCmd[0]);

                if (!vmcMap.containsKey(key)) {
                    getLogs().info("XinYuan vmcCmd:" + PortTools.showHex(vmcCmd));
                    getLogs().info("XinYuan vmcData:" + PortTools.showHex(vmcData));
                    getLogs().info("XinYuan vmcXor:" + PortTools.showHex(vmcXor));
                    getLogs().info("XinYuan vmc not found");
                    continue;
                }

                DevXinYuan.VMC vmc = vmcMap.get(key);

                if (vmc != DevXinYuan.VMC.VMC_41_POLL) {
                    getLogs().info("XinYuan vmcCmd:" + PortTools.showHex(vmcCmd));
                    getLogs().info("XinYuan vmcData:" + PortTools.showHex(vmcData));
                    getLogs().info("XinYuan vmcXor:" + PortTools.showHex(vmcXor));
                    getLogs().info("XinYuan vmc:" + vmc.name());
                }

                switch (vmc) {
                    case VMC_41_POLL:
                        if (getCountBySendBuffer() > 0) {
                            byte[] cmdBytes = getSendBufferByFirst();

                            if (cmdBytes.length == (4+cmdBytes[3]+1)) {
                                for (int sendCount=1; sendCount <=5; sendCount++) {
                                    rs232Dev.send(cmdBytes);
                                    getLogs().info("XinYuan Send:" + PortTools.showHex(cmdBytes));

                                    byte[] vmcBuffer = rs232Dev.readListen(0, 1);
                                    if (vmcBuffer.length > 2) {
                                        key = Byte.valueOf(vmcBuffer[2]);

                                        if (vmcMap.containsKey(key)) {
                                            vmc = vmcMap.get(key);

                                            if (vmc == null) continue;

                                            switch (vmc) {
                                                case VMC_42_ACK:
                                                    publishReadBuffer(vmc.getBytes());
                                                    break;
                                            }
                                        }
                                    }
                                }
                            } else {
                                logs.debug("cmd length error:"+PortTools.showHex(cmdBytes));
                                logs.clearMessage();
                            }
                            removeSendBufferByFirst();
                        } else {
                            rs232Dev.send(devXinYuan.sendACKByIsShow(false));
                        }
                        break;
                    case VMC_02_CHECK_SLOT_STATUS:
                        publishReadBuffer(PortTools.concatByteArrays(vmcCmd[0], vmcData[1]));
                        rs232Dev.send(devXinYuan.sendACK());
                        break;
                    case VMC_04_BUY_STATUS:
                        publishReadBuffer(PortTools.concatByteArrays(vmcCmd[0], vmcData[1]));
                        rs232Dev.send(devXinYuan.sendACK());
                        break;
                    case VMC_38_GIVE_CHANGE_MODE:
                        publishReadBuffer(PortTools.concatByteArrays(vmcCmd[0], vmcData[1]));
                        rs232Dev.send(devXinYuan.sendACK());
                        break;
                    case VMC_21_GET_MONEY:
                        int number21 = PortTools.byte8ToInt(vmcData[2], vmcData[3], vmcData[4], vmcData[5])/100;
                        publishReadBuffer(PortTools.concatByteArrays(vmcCmd[0], vmcData[1]), PortTools.intToByte8(number21, 2));
                        rs232Dev.send(devXinYuan.sendACK());
                        break;
                    case VMC_23_NOW_GET_TOTAL:
                        int number23 = PortTools.byte8ToInt(vmcData[1], vmcData[2], vmcData[3], vmcData[4])/100;
                        publishReadBuffer(PortTools.concatByteArrays(vmcCmd[0], (byte)0x00), PortTools.intToByte8(number23, 2));
                        rs232Dev.send(devXinYuan.sendACK());
                        break;
                    case VMC_26_GIVE_CHANGE:
                        int bill26 = PortTools.byte8ToInt(vmcData[1], vmcData[2], vmcData[3], vmcData[4])/100;
                        int coin26 = PortTools.byte8ToInt(vmcData[5], vmcData[6], vmcData[7], vmcData[8])/100;
                        int number26 = bill26 + coin26;
                        publishReadBuffer(PortTools.concatByteArrays(vmcCmd[0], (byte)0x00), PortTools.intToByte8(number26, 2));
                        rs232Dev.send(devXinYuan.sendACK());
                        break;
                    case VMC_27_IN_COME:
                        int number27 = PortTools.byte8ToInt(vmcData[1], vmcData[2], vmcData[3], vmcData[4])/100;
                        publishReadBuffer(PortTools.concatByteArrays(vmcCmd[0], (byte)0x00), PortTools.intToByte8(number27, 2));
                        rs232Dev.send(devXinYuan.sendACK());
                        break;
                    case VMC_29_MONEY_SWITCH:
                        publishReadBuffer(PortTools.concatByteArrays(vmcCmd[0], vmcData[1]));
                        rs232Dev.send(devXinYuan.sendACK());
                        break;
                    case VMC_31_SYNC_PACK_NO:
                        publishReadBuffer(PortTools.concatByteArrays(vmcCmd[0], vmcData[0]));
                        rs232Dev.send(devXinYuan.sendACK());
                        break;
                    case VMC_32_GET_VERSION:
                        publishReadBuffer(PortTools.concatByteArrays(vmcCmd[0], vmcData[1]));
                        rs232Dev.send(devXinYuan.sendACK());
                        break;
                    case VMC_52_CHECK_VMC_STATUS:
                        //溫度:vmcData[7]
//                        getLogs().info(PortTools.showHex(vmcData));
                        DevXinYuanController.setTemperature(vmcData[5]);
                        rs232Dev.send(devXinYuan.sendACK());
                        break;
                    default:
                        rs232Dev.send(devXinYuan.sendACK());
                }
            } catch (LogsIOException e) {
                getLogs().warning(e);
            }
        }
    }

//    @Override
//    protected void exception(ErrorCode errorCode, String message, HandlerMain handlerMain) {
//        setRun(false);
//        handlerMain.error(getClass().getSimpleName(), errorCode, message);
//    }

    @Override
    protected Class<?> setCls() {
        return getClass();
    }

    @Override
    protected String description() {
        return getClass().getSimpleName();
    }

    public static int getTemperature() {
        return temperature;
    }

    public static double getTemp() {
        return temp;
    }

    public static void setTemperature(int temperature) {
        DevXinYuanController.temperature = temperature;
    }

    public static void setTemp(double temp) {
        DevXinYuanController.temp = temp;
    }
}
